import CryptoJS from 'crypto-js'

// sha256哈希加密
export async function hashEncrypt(message) {
  if (window.crypto.subtle) {
    const msgUint8 = new TextEncoder().encode(message) // 编码为（utf-8）Uint8Array
    const hashBuffer = await window.crypto.subtle.digest('SHA-256', msgUint8) // 计算消息的哈希值
    const hashArray = Array.from(new Uint8Array(hashBuffer)) // 将缓冲区转换为字节数组
    const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('') // 将字节数组转换为十六进制字符串

    return hashHex
  }

  return CryptoJS.SHA256(message).toString()
}

function bytesToHexString(buffer) {
  let hexStr = ''
  const view = new Uint8Array(buffer)
  for (let i = 0; i < view.length; i++) {
    const hex = view[i].toString(16)
    hexStr += hex.length === 1 ? '0' + hex : hex
  }
  return hexStr
}

function hexStringToBytes(string) {
  const view = new Uint8Array(string.length / 2)
  for (let i = 0; i < view.length; i++) {
    view[i] = Number.parseInt(string.slice(i * 2, i * 2 + 2), 16)
  }
  return view
}

function base64ToBytes(base64) {
  const binString = atob(base64)
  return Uint8Array.from(binString, (m) => m.codePointAt(0))
}

function bytesToBase64(bytes) {
  bytes = new Uint8Array(bytes)

  const binString = Array.from(bytes, (byte: any) => String.fromCodePoint(byte)).join('')
  return btoa(binString)
}

const keyStr = '110e4a4aeede9845028802131eea0ea6' // 16进制16字节
// 生成aes密钥
async function generateKey() {
  const key = await window.crypto.subtle.generateKey(
    {
      name: 'AES-CBC',
      length: 128 // bits
    },
    true,
    ['encrypt', 'decrypt']
  )
  const exportedKeyBuffer = await window.crypto.subtle.exportKey('raw', key)
  const exportedKeyStr = bytesToHexString(exportedKeyBuffer)

  return exportedKeyStr
}
// 生成iv, 16进制16字节
function generateIv() {
  const array = new Uint8Array(16)
  const view = window.crypto.getRandomValues(array)
  const ivStr = bytesToHexString(view)

  return ivStr
}
// aes加密
export async function encrypt(message) {
  const ivStr = generateIv()

  if (window.crypto.subtle) {
    const enc = new TextEncoder()
    const encoded = enc.encode(message)
    const iv = hexStringToBytes(ivStr)
    const rawKey = hexStringToBytes(keyStr)
    const key = await window.crypto.subtle.importKey(
      'raw',
      rawKey,
      {
        name: 'AES-CBC',
        length: 128
      },
      true,
      ['encrypt', 'decrypt']
    )

    const encodedBuffer = await window.crypto.subtle.encrypt(
      { name: 'AES-CBC', iv: iv },
      key,
      encoded
    )

    return `${ivStr}:${bytesToBase64(encodedBuffer)}`
  }

  const key = CryptoJS.enc.Hex.parse(keyStr)
  const iv = CryptoJS.enc.Hex.parse(ivStr)
  const encrypted = CryptoJS.AES.encrypt(message, key, { iv: iv })
  const ciphertext = encrypted.toString() // base64

  return `${ivStr}:${ciphertext}`
}
// aes解密
export async function decrypt(text) {
  const ivStr = text.split(':')[0]
  const ciphertext = text.split(':')[1]
  const ciphertextData = base64ToBytes(ciphertext)

  if (window.crypto.subtle) {
    const iv = hexStringToBytes(ivStr)
    const rawKey = hexStringToBytes(keyStr)
    const key = await window.crypto.subtle.importKey(
      'raw',
      rawKey,
      {
        name: 'AES-CBC',
        length: 128
      },
      true,
      ['encrypt', 'decrypt']
    )

    const decodedBuffer = await window.crypto.subtle.decrypt(
      { name: 'AES-CBC', iv: iv },
      key,
      ciphertextData
    )

    const dec = new TextDecoder()
    const originalText = dec.decode(decodedBuffer)

    return originalText
  }

  const key = CryptoJS.enc.Hex.parse(keyStr)
  const iv = CryptoJS.enc.Hex.parse(ivStr)
  // ciphertext base64字符串
  const bytes = CryptoJS.AES.decrypt(ciphertext, key, { iv: iv })
  const originalText = bytes.toString(CryptoJS.enc.Utf8)

  return originalText
}
